﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;

namespace GameViewer.Ogre
{

    /** The pixel format used for images, textures, and render surfaces */
    enum PixelFormat
    {
        /// Unknown pixel format.
        PF_UNKNOWN = 0,
        /// 8-bit pixel format, all bits luminace.
        PF_L8 = 1,
        PF_BYTE_L = PF_L8,
        /// 16-bit pixel format, all bits luminace.
        PF_L16 = 2,
        PF_SHORT_L = PF_L16,
        /// 8-bit pixel format, all bits alpha.
        PF_A8 = 3,
        PF_BYTE_A = PF_A8,
        /// 8-bit pixel format, 4 bits alpha, 4 bits luminance.
        PF_A4L4 = 4,
        /// 2 byte pixel format, 1 byte luminance, 1 byte alpha
        PF_BYTE_LA = 5,
        /// 16-bit pixel format, 5 bits red, 6 bits green, 5 bits blue.
        PF_R5G6B5 = 6,
        /// 16-bit pixel format, 5 bits red, 6 bits green, 5 bits blue.
        PF_B5G6R5 = 7,
        /// 8-bit pixel format, 2 bits blue, 3 bits green, 3 bits red.
        PF_R3G3B2 = 31,
        /// 16-bit pixel format, 4 bits for alpha, red, green and blue.
        PF_A4R4G4B4 = 8,
        /// 16-bit pixel format, 5 bits for blue, green, red and 1 for alpha.
        PF_A1R5G5B5 = 9,
        /// 24-bit pixel format, 8 bits for red, green and blue.
        PF_R8G8B8 = 10,
        /// 24-bit pixel format, 8 bits for blue, green and red.
        PF_B8G8R8 = 11,
        /// 32-bit pixel format, 8 bits for alpha, red, green and blue.
        PF_A8R8G8B8 = 12,
        /// 32-bit pixel format, 8 bits for blue, green, red and alpha.
        PF_A8B8G8R8 = 13,
        /// 32-bit pixel format, 8 bits for blue, green, red and alpha.
        PF_B8G8R8A8 = 14,
        /// 32-bit pixel format, 8 bits for red, green, blue and alpha.
        PF_R8G8B8A8 = 28,
        /// 32-bit pixel format, 8 bits for red, 8 bits for green, 8 bits for blue
        /// like PF_A8R8G8B8, but alpha will get discarded
        PF_X8R8G8B8 = 26,
        /// 32-bit pixel format, 8 bits for blue, 8 bits for green, 8 bits for red
        /// like PF_A8B8G8R8, but alpha will get discarded
        PF_X8B8G8R8 = 27,
#if OGRE_ENDIAN == OGRE_ENDIAN_BIG
        /// 3 byte pixel format, 1 byte for red, 1 byte for green, 1 byte for blue
        PF_BYTE_RGB = PF_R8G8B8,
        /// 3 byte pixel format, 1 byte for blue, 1 byte for green, 1 byte for red
        PF_BYTE_BGR = PF_B8G8R8,
        /// 4 byte pixel format, 1 byte for blue, 1 byte for green, 1 byte for red and one byte for alpha
        PF_BYTE_BGRA = PF_B8G8R8A8,
        /// 4 byte pixel format, 1 byte for red, 1 byte for green, 1 byte for blue, and one byte for alpha
        PF_BYTE_RGBA = PF_R8G8B8A8,
#else
		/// 3 byte pixel format, 1 byte for red, 1 byte for green, 1 byte for blue
		PF_BYTE_RGB = PF_B8G8R8,
		/// 3 byte pixel format, 1 byte for blue, 1 byte for green, 1 byte for red
		PF_BYTE_BGR = PF_R8G8B8,
		/// 4 byte pixel format, 1 byte for blue, 1 byte for green, 1 byte for red and one byte for alpha
		PF_BYTE_BGRA = PF_A8R8G8B8,
		/// 4 byte pixel format, 1 byte for red, 1 byte for green, 1 byte for blue, and one byte for alpha
		PF_BYTE_RGBA = PF_A8B8G8R8,
#endif
        /// 32-bit pixel format, 2 bits for alpha, 10 bits for red, green and blue.
        PF_A2R10G10B10 = 15,
        /// 32-bit pixel format, 10 bits for blue, green and red, 2 bits for alpha.
        PF_A2B10G10R10 = 16,
        /// DDS (DirectDraw Surface) DXT1 format
        PF_DXT1 = 17,
        /// DDS (DirectDraw Surface) DXT2 format
        PF_DXT2 = 18,
        /// DDS (DirectDraw Surface) DXT3 format
        PF_DXT3 = 19,
        /// DDS (DirectDraw Surface) DXT4 format
        PF_DXT4 = 20,
        /// DDS (DirectDraw Surface) DXT5 format
        PF_DXT5 = 21,
        // 16-bit pixel format, 16 bits (float) for red
        PF_FLOAT16_R = 32,
        // 48-bit pixel format, 16 bits (float) for red, 16 bits (float) for green, 16 bits (float) for blue
        PF_FLOAT16_RGB = 22,
        // 64-bit pixel format, 16 bits (float) for red, 16 bits (float) for green, 16 bits (float) for blue, 16 bits (float) for alpha
        PF_FLOAT16_RGBA = 23,
        // 16-bit pixel format, 16 bits (float) for red
        PF_FLOAT32_R = 33,
        // 96-bit pixel format, 32 bits (float) for red, 32 bits (float) for green, 32 bits (float) for blue
        PF_FLOAT32_RGB = 24,
        // 128-bit pixel format, 32 bits (float) for red, 32 bits (float) for green, 32 bits (float) for blue, 32 bits (float) for alpha
        PF_FLOAT32_RGBA = 25,
        // 32-bit, 2-channel s10e5 floating point pixel format, 16-bit green, 16-bit red
        PF_FLOAT16_GR = 35,
        // 64-bit, 2-channel floating point pixel format, 32-bit green, 32-bit red
        PF_FLOAT32_GR = 36,
        // Depth texture format
        PF_DEPTH = 29,
        // 64-bit pixel format, 16 bits for red, green, blue and alpha
        PF_SHORT_RGBA = 30,
        // 32-bit pixel format, 16-bit green, 16-bit red
        PF_SHORT_GR = 34,
        // 48-bit pixel format, 16 bits for red, green and blue
        PF_SHORT_RGB = 37,
        /// PVRTC (PowerVR) RGB 2 bpp
        PF_PVRTC_RGB2 = 38,
        /// PVRTC (PowerVR) RGBA 2 bpp
        PF_PVRTC_RGBA2 = 39,
        /// PVRTC (PowerVR) RGB 4 bpp
        PF_PVRTC_RGB4 = 40,
        /// PVRTC (PowerVR) RGBA 4 bpp
        PF_PVRTC_RGBA4 = 41,
        // Number of pixel formats currently defined
        PF_COUNT = 42
    };

    /** Enum identifying the texture type
    */
    enum TextureType
    {
        /// 1D texture, used in combination with 1D texture coordinates
        TEX_TYPE_1D = 1,
        /// 2D texture, used in combination with 2D texture coordinates (default)
        TEX_TYPE_2D = 2,
        /// 3D volume texture, used in combination with 3D texture coordinates
        TEX_TYPE_3D = 3,
        /// 3D cube map, used in combination with 3D texture coordinates
        TEX_TYPE_CUBE_MAP = 4
    };

    public class OgreMaterial
    {
        public OgreMaterial(string name)
        {
            this.mName = name;
            OgreMaterialManager.Instance.AddMaterial(this);
        }

        private string mName;
        public string Name
        {
            get
            {
                return mName;
            }
            set
            {
                mName = value;
            }
        }

        private List<OgreTechnique> mTechniques = new List<OgreTechnique>();
        public List<OgreTechnique> Techniques
        {
            get
            {
                return mTechniques;
            }
        }

        public int NumTechniques
        {
            get
            {
                return mTechniques.Count;
            }
        }

        public OgreTechnique CreateTechnique()
        {
            OgreTechnique tech = new OgreTechnique(this);            
            this.mTechniques.Add(tech);
            return tech;
        }

        public int GetTechniqueIndex(OgreTechnique tech)
        {
            return mTechniques.FindIndex(delegate(OgreTechnique tech1)
            {
                return tech == tech1;
            });
        }

        public OgreTechnique this[string name]
        {
            get
            {
                return mTechniques.Find(delegate(OgreTechnique tech)
                {
                    return tech.Name == name;
                });
            }
        }

        public OgreTechnique this[int index]
        {
            get
            {
                if (index < NumTechniques)
                {
                    return mTechniques[index];
                }
                else
                {
                    return null;
                }
            }
        }
    }

    public class OgreTechnique
    {
        public OgreTechnique(OgreMaterial material)
        {
            this.mParent = material;
        }

        private OgreMaterial mParent;
        public OgreMaterial Parent
        {
            get
            {
                return mParent;
            }
        }

        private string mName;
        public string Name
        {
            get
            {
                return mName;
            }
            set
            {
                mName = value;
            }
        }


        private List<OgrePass> mPasses = new List<OgrePass>();
        public List<OgrePass> Passes
        {
            get
            {
                return mPasses;
            }
        }

        public OgrePass CreatePass()
        {
            OgrePass pass = new OgrePass(this);
            this.mPasses.Add(pass);
            return pass;
        }

        public int NumPasses
        {
            get
            {
                return mPasses.Count;
            }
        }

        public OgrePass this[string name]
        {
            get
            {
                return mPasses.Find(delegate(OgrePass tech)
                {
                    return tech.Name == name;
                });
            }
        }

        public OgrePass this[int index]
        {
            get
            {
                if (index < mPasses.Count)
                {
                    return mPasses[index];
                }
                else
                {
                    return null;
                }
            }
        }
    }

    public class OgrePass
    {
        public OgrePass(OgreTechnique tech)
        {
            this.mParent = tech;
            this.mIndex = mParent.NumPasses;
        }

        private int mIndex;
        public int Index
        {
            get
            {
                return mIndex;
            }
        }

        private string mName;
        public string Name
        {
            get
            {
                return mName;
            }
            set
            {
                mName = value;
            }
        }

        private OgreTechnique mParent;
        public OgreTechnique Parent
        {
            get
            {
                return mParent;
            }
        }

        private List<OgreTextureUnitState> mTextureUnitStates = new List<OgreTextureUnitState>();
        public List<OgreTextureUnitState> TextureUnitStates
        {
            get
            {
                return mTextureUnitStates;
            }
        }

        private Color mAmbient;
        public Color Ambient
        {
            get
            {
                return mAmbient;
            }
            set
            {
                mAmbient = value;
            }
        }

        private Color mDiffuse;
        public Color Diffuse
        {
            get
            {
                return mDiffuse;
            }
            set
            {
                mDiffuse = value;
            }
        }

        private Color mSpecular;
        public Color Specular
        {
            get
            {
                return mSpecular;
            }
            set
            {
                mSpecular = value;
            }
        }

        private Color mEmissive;
        public Color Emissive
        {
            get
            {
                return mEmissive;
            }
            set
            {
                mEmissive = value;
            }
        }

        public OgreTextureUnitState CreateTextureUnitState()
        {
            OgreTextureUnitState tus = new OgreTextureUnitState(this);
            this.mTextureUnitStates.Add(tus);
            return tus;
        }

        public int NumTextureUnitStates
        {
            get
            {
                return this.mTextureUnitStates.Count;
            }
        }

        public int GetTextureUnitStateIndex(OgreTextureUnitState tus)
        {
            return mTextureUnitStates.FindIndex(delegate(OgreTextureUnitState tus1)
            {
                return tus1 == tus;
            });
        }

        public OgreTextureUnitState this[string name]
        {
            get
            {
                return mTextureUnitStates.Find(delegate(OgreTextureUnitState tech)
                {
                    return tech.Name == name;
                });
            }
        }

        public OgreTextureUnitState this[int index]
        {
            get
            {
                if (index < NumTextureUnitStates)
                {
                    return mTextureUnitStates[index];
                }
                else
                {
                    return null;
                }
            }
        }
    }

    public class OgreTextureUnitState
    {
        public OgrePass Parent;
        public string Name;
        public string TextureName;

        public OgreTextureUnitState(OgrePass pass)
        {
            this.Parent = pass;
        }
    }
}
